<?php

namespace App\Kuafu\WaiMai\Service;

use App\Kuafu\Config\Model\ConfigModel;
use App\Kuafu\Mqtt\Enum\MqttCodeEnum;
use App\Kuafu\Mqtt\Service\MqttService;
use App\Kuafu\Mybank\Service\MybankBrokerageService;
use App\Kuafu\Nsq\Enum\NsqCodeEnum;
use App\Kuafu\Nsq\Jobs\NsqSendJob;
use App\Kuafu\Nsq\Service\NsqService;
use App\Kuafu\Order\Enum\CodeEnum;
use App\Kuafu\Shop\Service\ShopService;
use App\Kuafu\WaiMai\Channel\BaseWaiMai;
use App\Kuafu\WaiMai\Enum\ElmWaiMaiEnum;
use App\Kuafu\WaiMai\Enum\MtWaiMaiEnum;
use App\Kuafu\WaiMai\Enum\WaiMaiCodeEnum;
use App\Kuafu\WaiMai\Enum\WaiMaiDBEnum;
use App\Kuafu\WaiMai\Exceptions\WaiMaiException;
use App\Kuafu\WaiMai\Jobs\WaiMaiDelayTask;
use App\Kuafu\WaiMai\Model\WaiMaiOrderIdShopIdMappingModel;
use App\Kuafu\WaiMai\Model\WaiMaiOrderModel;
use App\Kuafu\WaiMai\Model\WaiMaiOrderDetailModel;
use App\Kuafu\WaiMai\Model\WaiMaiShopMappingModel;
use App\Library\FeiShu\SendFs;
use App\Library\SnowFlake\SnowFlake;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class ElmWaiMaiOrderService extends BaseWaiMaiOrderService
{
    private ?array           $messageArr;
    private int              $orderId;
    private WaiMaiOrderModel $waiMaiOrder;
    private string           $thirdShopId;
    private int              $shopId;
    private int              $type = 0;
    private int              $orderStatus;
    private int              $hand;

    /**
     * @param int $hand 0自动回调模式 1手动模式
     * @return $this
     */
    public function init(int $hand = 1): self
    {
        $this->hand = $hand;
        $this->type = $this->requestData['type'] ?? 0;

        if ($hand == 1) {
            $this->messageArr = $this->requestData;
        } else {
            $this->messageArr = json_decode($this->requestData['message'] ?? '', true);
        }

        if (isset($this->messageArr['orderId']) && $this->messageArr['orderId']) {
            $this->orderId = (int)$this->messageArr['orderId'];
        } elseif (isset($this->messageArr['id']) && $this->messageArr['id']) {
            $this->orderId = (int)$this->messageArr['id'];
        } elseif (config('app.pressure')) {
            $this->orderId = SnowFlake::nextIdCache();
        } else {
            $this->orderId = 0;
        }

        if (isset($this->requestData['shopId']) && $this->requestData['shopId']) {
            $this->thirdShopId = (string)$this->requestData['shopId'];
        } elseif (isset($this->messageArr['shopId']) && $this->messageArr['shopId']) {
            $this->thirdShopId = (string)$this->messageArr['shopId'];
        } else {
            $this->thirdShopId = '';
        }

        // 转换shopId
        $this->shopId = WaiMaiShopMappingModel::getShopIdByThirdShopId($this->thirdShopId, $this->sourceType);

        $this->waiMaiOrder = new WaiMaiOrderModel(['orderId' => $this->orderId, 'shopId' => $this->shopId]);

        $this->orderStatus = (int)WaiMaiOrderModel::suffix($this->shopId)
                                                  ->where('orderId', $this->orderId)
                                                  ->value('orderStatus') ?? 0;

        return $this;
    }

    public function run(int $hand = 0): bool
    {
        $this->init($hand);

        // 转换shopId
        if (!$this->shopId) {

            // 店铺未绑定门店
            BaseWaiMaiOrderService::$errMsg = WaiMaiCodeEnum::CODE_TEXT[WaiMaiCodeEnum::ERR_ELM_EMPTY_SHOP_MAPPING];
            return true;
        }

        Log::channel('waiMai')->info('elm run log', [
            'shopId'      => $this->shopId,
            'orderId'     => $this->orderId,
            'type'        => $this->type,
            'thirdShopId' => $this->thirdShopId,
            'orderStatus' => $this->orderStatus,
            'hand'        => $this->hand,
        ]);

        switch ($this->type) {
//            case ElmWaiMaiEnum::TYPE_10:
//                $s = $this->createOrder();
//                break;
            case ElmWaiMaiEnum::TYPE_217:
                $s = $this->createOrderV2();
                break;
            case ElmWaiMaiEnum::TYPE_12:
                $s = $this->acceptOrder();
                break;
            case ElmWaiMaiEnum::TYPE_14:
            case ElmWaiMaiEnum::TYPE_15:
            case ElmWaiMaiEnum::TYPE_17:
            case ElmWaiMaiEnum::TYPE_33: // 有部分退款可能
            case ElmWaiMaiEnum::TYPE_39:
                $s = $this->cancelOrder();
                break;
            case ElmWaiMaiEnum::TYPE_18:
                $s = $this->completeOrder();
                break;
            case ElmWaiMaiEnum::TYPE_20:
            case ElmWaiMaiEnum::TYPE_30:
                $s = $this->applyCancelOrder();
                break;
            case ElmWaiMaiEnum::TYPE_21:
            case ElmWaiMaiEnum::TYPE_22:
                $s = $this->recallCancelOrder();
                break;
            case ElmWaiMaiEnum::TYPE_31:
            case ElmWaiMaiEnum::TYPE_32:
                $s = $this->rollCompleteOrder();
                break;
            case ElmWaiMaiEnum::TYPE_53:
                $s = $this->waitDeliver();
                break;
            case ElmWaiMaiEnum::TYPE_55:
                $s = $this->deliveringOrder();
                break;

            // TODO
            case ElmWaiMaiEnum::TYPE_91:
                $s = $this->shopStatus();
                break;

            case ElmWaiMaiEnum::TYPE_100:
                $s = $this->shopUnbind();
                break;

            default:
                $s = false;
                break;
        }

        return $s;
    }

    /**
     * 创建饿了么订单
     * @param array $requestData
     */
    public function createOrder(): bool
    {
        // 针对每个订单加锁
        $this->lockFuncBefore($this->orderId, __FUNCTION__);

        // 转换shopId
        $data['shopId'] = $this->shopId;

        // 判断订单是否存在
        $order = WaiMaiOrderModel::suffix($this->shopId)->where('orderId', $this->orderId)->first();
        if ($order) {

            // 没接单的话，要接单
            if ($order->orderStatus == WaiMaiDBEnum::ORDER_STATUS_1) {

                // 自动接单
                BaseWaiMai::getIns($this->sourceType, $data['shopId'])->acceptOrder($this->orderId);
            }

            // 存在的直接忽略，饿了么会莫名的返回推订单过来
            BaseWaiMaiOrderService::$errMsg = '订单已存在';

            $this->lockFuncAfter($this->orderId, __FUNCTION__);

            return true;
        }

        $data['brandId'] = ShopService::getShopInfo($data['shopId'])->brandId ?? 1;

        // 优惠的配送费
        $discountShipping = abs($this->bcmul100($this->messageArr['logisticsActivity']['amount'] ?? 0));

        $data['orderId']            = $this->orderId;
        $orderCreatedAt             = $data['createdAt'] = $data['updatedAt'] = strtotime($this->messageArr['createdAt']) ?? time();
        $data['sourceType']         = $this->sourceType;
        $data['serialNum']          = $this->messageArr['daySn'] ?? 0;
        $data['originalPrice']      = $this->bcmul100($this->messageArr['originalPrice'] ?? 0) + $discountShipping; // 饿了么的原价 = 他给的原价 + 优惠的配送费
        $data['payPrice']           = $this->bcmul100($this->messageArr['totalPrice'] ?? 0);
        $data['shippingPrice']      = $this->bcmul100($this->messageArr['deliverFee'] ?? 0); // 用户支付的配送费
        $data['originalShippingPrice'] = $data['shippingPrice'] + $discountShipping; // 原始的配送费
        $data['packingPrice']       = $this->bcmul100($this->messageArr['packageFee'] ?? 0);
        $data['orderStatus']        = $orderStatus = $this->convertOrderStatus($this->messageArr['status']);
        $data['completeTime']       = $orderStatus == WaiMaiDBEnum::ORDER_STATUS_5 ? strtotime($this->messageArr['activeAt']) : 0;
        $data['acceptTime']         = $orderStatus >= WaiMaiDBEnum::ORDER_STATUS_2 ? strtotime($this->messageArr['activeAt']) : 0;
        $data['remark']             = $this->messageArr['description'] ?? '';
        $data['platformPrice']      = $this->bcmul100(abs($this->messageArr['serviceFee'] ?? 0));
        $data['expectIncome']       = $this->bcmul100($this->messageArr['income'] ?? 0);
        $data['expectFast']         = ($this->messageArr['deliverTime'] ?? null) === null ? 1 : 0;
        $data['expectTime']         = (int)strtotime($this->messageArr['deliverTime'] ?? null); // 立即送达，这里为0
        $data['senderName']         = '';
        $data['senderPhone']        = '';
        $data['receiverName']       = $this->messageArr['consignee'] ?? '';
        $data['receiverPhone']      = $this->messageArr['consigneePhones'][0] ?? '';
        $data['receiverAddress']    = $this->messageArr['deliveryPoiAddress'] ?? '';
        $data['redPrice']           = $this->bcmul100(abs($this->messageArr['activityTotal'] ?? 0)) + $discountShipping; // 配送费优惠要单独加
        $data['redLists'] = json_encode(collect($this->messageArr['orderActivities'])
            ->add(['name' => '配送费优惠', 'amount' => bcdiv($discountShipping, 100, 2)])
//            ->where('categoryId', 15)
            ->map(function ($item) {
                $type = $item['type'] ?? 0;

                if ($item['amount'] == 0 && $type != 106) { // 106赠品
                    return null;
                }

                return [
                    'n' => $item['name'],
                    'p' => abs($this->bcmul100($item['amount'])),
                ];
            })->filter()->values()->toArray(), JSON_UNESCAPED_UNICODE);

        $data['fullReductionPrice'] = $this->bcmul100(abs(collect($this->messageArr['orderActivities'])
            ->where('type', 102)
            ->sum('amount')));

        $data['receiverPrivacyPhones'] = json_encode($this->messageArr['phoneList']);

        // 商家承担的支出金额
        $activityExpenditure = 0;

        // 1. 活动支出
        collect($this->messageArr['orderActivities'] ?? [])->each(function($item) use (&$activityExpenditure){
            $activityExpenditure = bcadd($activityExpenditure, $item['restaurantPart'] ?? 0, 2);
        });
        $data['activityExpenditure'] = abs($this->bcmul100($activityExpenditure));

        // 2.配送费支出
        $data['activityExpenditure'] += abs($this->bcmul100($this->messageArr['logisticsActivity']['restaurantPart'] ?? 0));

        // 优惠金额 = 菜品原价合计 + 包装费 - 营业收入
        $data['discountPrice'] = $data['originalPrice'] - $data['originalShippingPrice'] - $data['expectIncome'];

        // 其他支出 = 菜品原价合计 + 包装费 - 营业收入 - 平台服务费 - 商家活动支出
        $data['otherPrice'] = $data['discountPrice'] - $data['platformPrice'] - $data['activityExpenditure'];

        // 开票信息
        if (isset($this->messageArr['invoiced']) && $this->messageArr['invoiced'] == MtWaiMaiEnum::TAX_PAYER_OK) {
            $data['taxpayers'] = json_encode([
                WaiMaiDBEnum::TAX_CODE  => $this->messageArr['taxpayerId'] ?? '',
                WaiMaiDBEnum::TAX_TITLE => $this->messageArr['invoice'] ?? '',
                WaiMaiDBEnum::TAX_EMAIL => $this->messageArr['invoiceEmail'] ?? '',
                WaiMaiDBEnum::TAX_TYPE  => MtWaiMaiEnum::TAX_TEXT[$this->messageArr['invoiceType'] ?? ''] ?? '公司',
            ], JSON_UNESCAPED_UNICODE);
        } else {
            $data['taxpayers'] = "[]";
        }

        // 把菜篮子的菜品合并起来
        $detailArr = [];
        collect($this->messageArr['groups'] ?? [])->where('type', 'normal')
                                                  ->each(function ($item, $pocketId) use (&$detailArr) {
                                                      collect($item['items'])
                                                          ->each(function ($i) use (&$detailArr, $pocketId) {
                                                              $i['pocketId'] = $pocketId + 1;
                                                          $detailArr[] = $i;
                                                      });
                                                  });

        DB::connection('mysqlWaiMai')->beginTransaction();

        $this->waiMaiOrder->addData($data);

        // orderId -> shopId 映射表
        WaiMaiOrderIdShopIdMappingModel::addData($this->orderId, $this->shopId, $this->sourceType);

        $orderDetailData = [];

        foreach ($detailArr as $detail) {

            $productProperty = '';
            foreach ($detail['attributes'] ?? [] as $at) {
                $productProperty .= $at['name'] . ":" . $at['value'] . ';';
            }

            $orderDetailData[] = [
                'brandId'           => ShopService::getShopInfo($this->shopId)->brandId ?? 0,
                'shopId'            => $this->shopId,
                'orderId'           => $this->orderId,
                'productName'       => $productName = $detail['name'] ?? '',
                'productNameStandard' => preg_replace('/\[[^\]]*\]$/', '', $productName),
                'productProperty'   => $productProperty,
                'unit'              => '份',
                'originalUnitPrice' => $originUnitPrice = $this->bcmul100($detail['price'] ?? 0),
                'num'               => $num = $detail['quantity'] ?? 0,
                'originalPrice'     => $originUnitPrice * $num,
                'createdAt'         => $orderCreatedAt,
                'updatedAt'         => $orderCreatedAt,
                'productType'       => WaiMaiOrderDetailModel::PRODUCT_TYPE_1,
                'sourceType'        => $this->sourceType,
                'pocketId'          => $detail['pocketId'] ?? 1,
                'uniqueId'          => $detail['uniqueId'] ?? '',
                'skuId'             => $detail['skuId'] ?? '',
            ];
        }

        // 菜品明细加上包装物
        $this->pushPacking($orderDetailData, $data['packingPrice']);

        // 平台菜的优惠
        $this->shareDetailDiscount($orderDetailData, $data['discountPrice']);

        // 平摊所有菜品的收入
        $this->shareDetailIncomes($orderDetailData, $data['expectIncome']);

        WaiMaiOrderDetailModel::addData($orderDetailData);

        DB::connection('mysqlWaiMai')->commit();

        if (!config('app.pressure')) {

            $orderStatus = BaseWaiMai::getIns($this->sourceType, $data['shopId'])->getOrderDetail($this->orderId)['data']['orderStatus'] ?? -1;
            Log::info("ELM ACCEPT ORDER STATUS: {$orderStatus} orderId: {$this->orderId}");

            if ($orderStatus == WaiMaiDBEnum::ORDER_STATUS_2) {

                // 直接处理接单
                $this->messageArr['state'] = ElmWaiMaiEnum::ORDER_STATUS_VALID;
                $this->messageArr['updateTime'] = time();
                $this->acceptOrder();
            } else {

                // 自动接单
                BaseWaiMai::getIns($this->sourceType, $data['shopId'])->acceptOrder($this->orderId);
            }
        }

        // 自动出餐相关操作
        $this->autoFinish($data);

        $this->lockFuncAfter($this->orderId, __FUNCTION__);

        if ($this->hand == 1) {
            Log::info('eeeelm createV2 '.$this->shopId);
        } else {
            Log::info('eeeelm createV1 '.$this->shopId);
        }

        return true;
    }

    // 创建订单v2
    public function createOrderV2(): bool
    {
        $detail = BaseWaiMai::getIns($this->sourceType, $this->shopId, $this->thirdShopId)
                            ->getOrderDetail($this->orderId);
        if (!$detail['status']) {
            throw new WaiMaiException(WaiMaiCodeEnum::ERR_API_ORDER_DETAIL);
        }

        // 本地没有，补单
        $this->setRequestData($detail['oriData'])
             ->init()
             ->createOrder();

        return true;
    }

    // 商户接单
    public function acceptOrder(): bool
    {
        $orderStatus = $this->messageArr['state'] ?? '';
        $updateTime  = (int)($this->messageArr['updateTime'] ?? 0);
        if ($orderStatus != ElmWaiMaiEnum::ORDER_STATUS_VALID) {
            return false;
        }

        // 已完成、取消
        if (in_array($this->orderStatus, WaiMaiDBEnum::ORDER_STATUS_OVER)) {
            BaseWaiMaiOrderService::$errMsg = '订单状态已完结';
            return true;
        }

        $db = WaiMaiOrderModel::suffix($this->shopId)->where('orderId', $this->orderId)->count();
        if (!$db) {
            $repair = $this->repairOrder($this->shopId, $this->orderId);
            if (!$repair) {
                return false;
            }
        }

        $this->waiMaiOrder->acceptOrder($updateTime);

        // MQTT
        WaiMaiMqttService::getIns($this->shopId)
                         ->takeOutOrderOperate($this->sourceType, $this->orderId,
                             MqttCodeEnum::TAKE_OUT_OPERATE_TYPE_2);
        return true;
    }

    // 待配送
    public function waitDeliver(): bool
    {
        $this->waiMaiOrder->waitDeliver();

        // 已完成、取消
        if (in_array($this->orderStatus, WaiMaiDBEnum::ORDER_STATUS_OVER)) {
            BaseWaiMaiOrderService::$errMsg = '订单状态已完结';
            return true;
        }

        // MQTT
        (new MqttService(0, $this->shopId))->takeOutOrder($this->orderId, WaiMaiDBEnum::SOURCE_TYPE_ELM,
            MqttCodeEnum::TAKE_OUT_OPERATE_TYPE_6, []);
        return true;
    }

    // 配送中
    public function deliveringOrder(): bool
    {
        $senderName = $this->messageArr['name'] ?? '';
        $sendPhone  = $this->messageArr['phone'] ?? '';
        $this->waiMaiOrder->deliveringOrder($senderName, $sendPhone);

        // 已完成、取消
        if (in_array($this->orderStatus, WaiMaiDBEnum::ORDER_STATUS_OVER)) {
            BaseWaiMaiOrderService::$errMsg = '订单状态已完结';
            return true;
        }

        // MQTT
        (new MqttService(0, $this->shopId))->takeOutOrder($this->orderId, WaiMaiDBEnum::SOURCE_TYPE_ELM,
            MqttCodeEnum::TAKE_OUT_OPERATE_TYPE_3, []);

        return true;
    }

    // 订单完成
    public function completeOrder(): bool
    {
        $db = WaiMaiOrderModel::suffix($this->shopId)->where('orderId', $this->orderId)->count();
        if (!$db) {

            $repair = $this->repairOrder($this->shopId, $this->orderId);
            if (!$repair) {
                return false;
            }
        }

        $completeTime = $this->messageArr['updateTime'] ?? time();
        $this->waiMaiOrder->completeOrder($completeTime);

        $this->finishHook();

        // MQTT
        (new MqttService(0, $this->shopId))->takeOutOrder($this->orderId, WaiMaiDBEnum::SOURCE_TYPE_ELM,
            MqttCodeEnum::TAKE_OUT_OPERATE_TYPE_4, []);



        return true;
    }

    // 再次回滚，订单完成
    public function rollCompleteOrder(): bool
    {
        $refundType   = $this->messageArr['refundType'] ?? ElmWaiMaiEnum::REFUND_TYPE_TOTAL;
        $refundStatus = $this->messageArr['refundStatus'] ?? ElmWaiMaiEnum::REFUND_STATUS_APPLIED;
        $foodArr      = collect($this->messageArr['goodsList'] ?? [])->map(function ($item) {
            return [
                'name'      => $item['name'] ?? '',
                'skuId'     => (string)($item['skuId'] ?? ''),
                'refundNum' => $item['quantity'] ?? 0,
            ];
        });

        if ($refundType == ElmWaiMaiEnum::REFUND_TYPE_TOTAL) {

            // 全额
            $this->waiMaiOrder->completeOrder(null);
        } else {

            // 当前的订单状态
            $orderStatus = BaseWaiMai::getIns($this->sourceType, $this->shopId)->getOrderDetail($this->orderId)['data']['orderStatus'] ?? WaiMaiDBEnum::ORDER_STATUS_5;

            $connectionName = WaiMaiOrderDetailModel::suffix($this->shopId)->getConnectionName();

            // 部分退款 - 拒绝 // 失败
            if ($refundStatus == ElmWaiMaiEnum::REFUND_STATUS_REJECTED || $refundStatus == ElmWaiMaiEnum::REFUND_STATUS_FAILED) {
                DB::connection($connectionName)->beginTransaction();
                $this->waiMaiOrder->partRefundFinish(false, 0, $orderStatus);
                WaiMaiOrderDetailModel::partRefund($this->shopId, $this->orderId, $foodArr, false);
                DB::connection($connectionName)->commit();

                return true;
            }
        }

        $this->finishHook();

        return true;
    }

    // 订单直接取消 = 取消 + 全额/部分退款
    public function cancelOrder(): bool
    {
        $refundType = $this->messageArr['refundType'] ?? ElmWaiMaiEnum::REFUND_TYPE_TOTAL;
        $refundStatus = $this->messageArr['refundStatus'] ?? ElmWaiMaiEnum::REFUND_STATUS_APPLIED;
        $foodArr     = collect($this->messageArr['goodsList'] ?? [])->map(function ($item) {
            return [
                'name'      => $item['name'] ?? '',
                'skuId'     => (string)($item['skuId'] ?? ''),
                'refundNum' => $item['quantity'] ?? 0,
            ];
        });
        $foodArrKeyBy =  $foodArr->keyBy('skuId');

        if ($refundType == ElmWaiMaiEnum::REFUND_TYPE_TOTAL) {

            // 全额
            $this->waiMaiOrder->cancelOrderFinish();

            // MQTT
            (new MqttService(0, $this->shopId))
                ->takeOutOrder($this->orderId, WaiMaiDBEnum::SOURCE_TYPE_ELM, MqttCodeEnum::TAKE_OUT_OPERATE_TYPE_5, [
                    'needConfirm' => false,
                ]);
        } else {

            // 当前的订单状态
            $orderDetail = BaseWaiMai::getIns($this->sourceType, $this->shopId)
                                     ->getOrderDetail($this->orderId) ?? [];
            $orderStatus = $orderDetail['data']['orderStatus'] ?? WaiMaiDBEnum::ORDER_STATUS_5;

            $connectionName = WaiMaiOrderDetailModel::suffix($this->shopId)->getConnectionName();

            // 部分退款 - 同意
            if ($refundStatus == ElmWaiMaiEnum::REFUND_STATUS_SUCCESSFUL) {

                $refundInfo = BaseWaiMai::getIns($this->sourceType, $this->shopId)
                                                 ->refundAmountInfo($this->orderId)['data'] ?? [];

//                $platformRefundPrice = $refundInfo['platformRefundPrice'] ?? 0;
                $userRefundPrice     = $refundInfo['userReceivedAmount'] ?? 0;
                $packingPrice        = $refundInfo['packingBoxFee'] ?? 0;

                $financeOrder = BaseWaiMai::getIns($this->sourceType, $this->shopId)->financeOrder($this->orderId);
                $nowIncomes = $financeOrder['data']['incomes'] ?? 0;
                $reduceIncomes = $financeOrder['data']['lists']->where('reduceIncomes', '>', 0)->first()['reduceIncomes'] ?? 0;

                // 累计的退款原价
                $originalPrice = WaiMaiOrderDetailModel::suffix($this->shopId)
                                                       ->where('orderId', $this->orderId)
                                                       ->whereIn('skuId', $foodArr->pluck('skuId'))
                                                       ->groupBy('skuId')
                                                       ->get()
                                                       ->map(function ($item) use ($foodArrKeyBy) {
                                                           return $item->originalUnitPrice * ($foodArrKeyBy[$item->skuId]['refundNum'] ?? 0);
                                                       })->sum();

                DB::connection($connectionName)->beginTransaction();

                $this->waiMaiOrder->partRefundFinish(true, 0, $orderStatus, $userRefundPrice, $packingPrice, $originalPrice, $nowIncomes, $reduceIncomes);
                WaiMaiOrderDetailModel::partRefund($this->shopId, $this->orderId, $foodArr, true);

                DB::connection($connectionName)->commit();

                return true;
            }
        }

        $this->finishHook();

        return true;
    }

    // 用户发起取消
    public function applyCancelOrder(): bool
    {
        $reason = $this->messageArr['reason'] ?? '';
        $refundType = $this->messageArr['refundType'] ?? ElmWaiMaiEnum::REFUND_TYPE_TOTAL;
        $refundStatus = $this->messageArr['refundStatus'] ?? ElmWaiMaiEnum::REFUND_STATUS_APPLIED;

        // 当前的订单状态
        $orderStatus = BaseWaiMai::getIns($this->sourceType, $this->shopId)->getOrderDetail($this->orderId)['data']['orderStatus'] ?? WaiMaiDBEnum::ORDER_STATUS_5;

        // 发起退款
        if ($refundStatus == ElmWaiMaiEnum::REFUND_STATUS_APPLIED) {

            if ($refundType == ElmWaiMaiEnum::REFUND_TYPE_PART) {

                // 部分退
                $isPartRefund = WaiMaiDBEnum::IS_PART_REFUND_1;
            } else {

                // 全额退
                $isPartRefund = WaiMaiDBEnum::IS_PART_REFUND_0;
            }

            $this->waiMaiOrder->applyCancelOrder($orderStatus, (string)$reason, '', $isPartRefund);

            // MQTT
            (new MqttService(0, $this->shopId))
                ->takeOutOrder($this->orderId, WaiMaiDBEnum::SOURCE_TYPE_ELM, MqttCodeEnum::TAKE_OUT_OPERATE_TYPE_5, [
                    'needConfirm' => true,
                ]);

            return true;
        }

        return true;
    }

    // 取消订单失败、撤回取消订单
    public function recallCancelOrder(): bool
    {
        $apiOrder = BaseWaiMai::getIns($this->sourceType, 0)->getOrderDetail($this->orderId);
        if (!$apiOrder['status']) {
            throw new WaiMaiException(WaiMaiCodeEnum::ERR_API_ORDER_DETAIL);
        }

        $orderStatus = $apiOrder['data']['orderStatus'];

        $this->waiMaiOrder->recallCancelOrder($orderStatus);
        return true;
    }

    // TODO
    public function shopStatus(): bool
    {
        return true;
    }

    public function shopUnbind(): bool
    {
        return true;
    }

    // 后期修复异常状态
    public function repairStatus()
    {
        $data['orderStatus']  = $orderStatus = $this->convertOrderStatus($this->messageArr['status']);
        $data['completeTime'] = $orderStatus == WaiMaiDBEnum::ORDER_STATUS_5 ? strtotime($this->messageArr['activeAt']) : 0;
        $data['refundReason'] = $this->messageArr['cancelOrderDescription'] ?? '';
        if ($data['orderStatus'] == WaiMaiDBEnum::ORDER_STATUS_7) {
            $data['refundPrice'] = $data['refundPriceToUser'] = $this->bcmul100($this->messageArr['totalPrice'] ?? 0);
        }

        WaiMaiOrderModel::suffix($this->shopId)->where('orderId', $this->orderId)->update($data);

        $this->finishHook();

        return true;
    }

    // 结束触发的钩子
    public function finishHook(): void
    {
        $order = WaiMaiOrderModel::suffix($this->shopId)->where('orderId', $this->orderId)->first();
        if (!$order) {
            return;
        }

        try {
            if ($order->orderStatus != WaiMaiDBEnum::ORDER_STATUS_7) {

                dispatch(function () {

                    Log::info("elm finishHook in...{$this->orderId}");

                    $data = [];

                    $financeOrder         = BaseWaiMai::getIns($this->sourceType, $this->shopId)->financeOrder($this->orderId);
                    $data['expectIncome'] = $financeOrder['data']['incomes'] ?? 0;

                    if ($data['expectIncome'] > 0) {
                        WaiMaiOrderModel::suffix($this->shopId)->where('orderId', $this->orderId)->update($data);

                        $this->waiMaiOrder->saveBrokerage();
                    } else {
                        Log::info("elm finishHook expectIncome error", [
                            'orderId' => $this->orderId,
                            'shopId'  => $this->shopId,
                            'data'    => $data,
                        ]);
                    }
                })->delay(300)->onQueue('{RMS-API-WM-QUEUE}');

                // 判断是否前天以前的订单
                if ($order->completeTime > 0 && strtotime(date('Y-m-d')) - $order->completeTime > 86400) {
                    // 数据同步更新操作
                    $nsqService = new NsqService();
                    $nsqService->setTopic(NsqCodeEnum::ORDER_NSQ_UPDATE_SEND_QUEUE);
                    $nsqService->setBody([
                        'shopId'    => (string)$this->shopId,
                        'orderId'   => (string)$this->orderId,
                        'orderType' => CodeEnum::SOURCE_TYPE_WAIMAI,
                        'updatedAt' => (string)$order->completeTime
                    ]);
                    $nsqService->sendNsq();
                }
            }

        } catch (\Exception $e) {
            Log::warning($e);
        }
    }

    /**
     * 转换orderStatus
     * @param string $waiMaiOrderStatus
     * @return int
     */
    public static function convertOrderStatus(string $waiMaiOrderStatus): int
    {
        return [
                ElmWaiMaiEnum::ORDER_STATUS_PENDING     => WaiMaiDBEnum::ORDER_STATUS_0, // 未生效订单
                ElmWaiMaiEnum::ORDER_STATUS_UNPROCESSED => WaiMaiDBEnum::ORDER_STATUS_1, // 未处理订单
                ElmWaiMaiEnum::ORDER_STATUS_REFUNDING   => WaiMaiDBEnum::ORDER_STATUS_6, // 退单处理中
                ElmWaiMaiEnum::ORDER_STATUS_VALID       => WaiMaiDBEnum::ORDER_STATUS_2, // 已处理的有效订单
                ElmWaiMaiEnum::ORDER_STATUS_INVALID     => WaiMaiDBEnum::ORDER_STATUS_7, // 无效订单
                ElmWaiMaiEnum::ORDER_STATUS_SETTLED     => WaiMaiDBEnum::ORDER_STATUS_5, // 已完成订单
            ][$waiMaiOrderStatus] ?? WaiMaiDBEnum::ORDER_STATUS_0;
    }

    /**
     * 转换退款类型
     * @param string $refundType
     * @return int
     */
    public static function convertRefundType(string $refundType): int
    {
        return [
            ElmWaiMaiEnum::REFUND_TYPE_TOTAL => WaiMaiDBEnum::REFUND_TYPE_TOTAL,
            ElmWaiMaiEnum::REFUND_TYPE_PART  => WaiMaiDBEnum::REFUND_TYPE_PART,
        ][$refundType] ?? 0;
    }
}
